from fcntl import FASYNC

from numpy import true_divide
import cy_config
import cy_operate
import cy_request
import cy_log
import time
import cencelSymbolOrder
import server_config
import profit
import json
import more_server_config

class OpenMore:

    def __init__(self, base_section_prices, index):

        # 价格区间
        self.section_prices = base_section_prices

        # 当前使用的区间
        self.current_section_prices = base_section_prices

        # 区间中下单的id数据
        self.section_buy_orders = []

        # 卖出单
        self.section_sell_orders = []

        # 下标 用来记录这个开的第几个区间
        self.index = index

        # 区间开始时间
        self.start_time = cy_operate.getCurrentTime()

        # 网格间距
        self.more_interval_bl = 0.2

        self.config = {
            "more_by_u" : "0",
            "more_max_trad_amount" : 100000,
            "more_sell_increase" : '0.2'
        }

    # 获取服务器配置
    def checkConfig(self):

        time.sleep(cy_config.sleep_amount)

        # 检测当前服务器配置，设置区间运行状态
        # 读取redis中的配置
        try:
            configData = more_server_config.getConfigData(cy_config.user_id, cy_config.symbol)

            if configData:

                self.config['more_max_trad_amount'] = int(configData['more_max_trad_amount'])
                self.config['more_by_u'] = float(configData['more_by_u'])
                self.config['more_sell_increase'] = float(configData['more_sell_increase'])

                # 最大套单同步
                max_trad_amount = self.config['more_max_trad_amount']
                cy_config.max_more_trad_amount = max_trad_amount

                # 下单u
                cy_config.more_buy_quantity_by_u = self.config['more_by_u']

                # 利润间距
                sell_inc = self.config['more_sell_increase']
                cy_config.more_sell_increase = float(sell_inc)

                # 网格间距
                self.more_interval_bl = float(configData['more_interval_bl'])

            else:
                cy_log.printAndInLog_more('配置错误：' + str(configData))
        except Exception as e:
            cy_log.printAndInLog_more('=========== 报错 ============')
            cy_log.printAndInLog_more('获取配置报错：' + str(e))
            cy_log.printAndInLog_more('=========== 报错 ============')
        else:
            pass

    # 根据倍率设置当前区间
    def reloadCurrentQJ(self):

        time.sleep(cy_config.sleep_amount)

        # 每次开始，检测一遍当前的套单数量 对倍率重新进行设置

        try:

            # 初始化的时候设置为0.1  运行的按照bl走 1就是0.2 2就是0.3
            # 初始化的时候设置为0.1  运行的按照bl走 1就是0.2 2就是0.3

            open_main_type = cy_operate.checkOpenMainType(cy_config.symbol)

            # 如果当前价格大于当前K线开盘价 那么主多(空的间距*2,恢复多的间距和利润间距)
            # 如果当前价格小于当前K线开盘价 那么主空(多的间距*2,恢复空的间距和利润间距)

            if open_main_type == 1:
                # 主多 不做任何操作
                cy_config.more_buy_quantity_by_u = cy_config.more_buy_quantity_by_u * 2.5
            elif open_main_type == 2:
                # 主空 多的间距*2
                self.more_interval_bl = self.more_interval_bl * 5

            bl = self.more_interval_bl / 0.2 - 1
            bl = int(bl)

            self.current_section_prices = cy_operate.checkQJPriceCanOperater(self.section_prices, bl, True)

        except Exception as e:
            cy_log.printAndInLog_more('=========== 报错 ============')
            cy_log.printAndInLog_more('根据倍率设置当前区间报错：' + str(e))
            cy_log.printAndInLog_more('=========== 报错 ============')
        else:
            pass

    # 刷新当前需要检测卖出订单
    def reloadCurrentNeedCHeckSellOrders(self):

        time.sleep(cy_config.sleep_amount)

        need_check_sell_orders = []

        for section_sell_order_item in self.section_sell_orders:

            time.sleep(cy_config.min_sleep_amount)

            section_isSelled = section_sell_order_item['is_selled']

            if section_isSelled == False:

                need_check_sell_orders.append(section_sell_order_item)

        cy_log.printAndInLog_more('目前所有的卖单：' + str(need_check_sell_orders))

        cy_log.printAndInLog_more_sells(need_check_sell_orders)

        if len(need_check_sell_orders) <= 100:
            return need_check_sell_orders
        else:
            # 获取创建的时间，然后获取距离当前时间最近的15个订单
            need_check_sell_orders.sort(key=cy_operate.reload_add_time, reverse=True)

            # 获取前15个
            new_need_check_sell_orders = []

            for index in range(0, 97):
                time.sleep(cy_config.min_sleep_amount)

                new_item = need_check_sell_orders[index]
                new_need_check_sell_orders.append(new_item)

            cy_log.printAndInLog_more('目前可以检测的卖单：' + str(new_need_check_sell_orders))

            return new_need_check_sell_orders

    # 去检测之前buy单，是否已经交易，如果已经交易（持仓）那么就去挂为sell
    def checkBuyOrders(self):

        time.sleep(cy_config.sleep_amount)

        try:
            cy_log.printAndInLog_more('检测Buy的单')

            for section_buy_order_item in self.section_buy_orders:

                time.sleep(cy_config.min_sleep_amount)

                # 获取订单目前的情况
                section_isSell = section_buy_order_item['is_sell']

                if section_isSell == False:

                    section_orderID = section_buy_order_item['section_buy_newClientOrderId']

                    section_price = section_buy_order_item['price']

                    cy_log.printAndInLog_more('checkBuyOrders')

                    section_order = cy_operate.getOrderWithOrderId(section_orderID, True)

                    if section_order:

                        order_status = section_order['state']

                        # if order_status == 'filled' or order_status == 'partially_filled':
                        if order_status == 'filled':

                            cy_config.more_tao_dan_amount = cy_config.more_tao_dan_amount + 1

                            cy_log.printAndInLog_more('BUY 当前订单状态：' + order_status)

                            # if order_status == 'partially_filled':
                            #     # 部分成交后，撤销买入挂单，然后获取这个挂单成交的数量和对应的买入价格 然后挂出卖出
                            #     # 撤销订单
                            #     cy_request.cencel_orderwithCustomerId(cy_config.symbol, section_orderID, True)

                            #     # 再获取一下订单 然后挂出目前的数量
                            #     cy_log.printAndInLog_more('部分成交 所以撤销后重新获取一下订单的信息用来去挂出')
                            #     section_order = cy_operate.getOrderWithOrderId(section_orderID, True)

                            c_my_order_price = section_order['fillPx']
                            c_my_order_origQty = section_order['fillSz']
                            c_my_order_status = section_order['state']

                            more_sell_increase = section_buy_order_item['current_interval']

                            cy_log.printAndInLog_more('BUY 当前订单状态：' + c_my_order_status + ' 订单价格：' + c_my_order_price + ' 订单数量：' + c_my_order_origQty + ' 自定义id: ' + section_orderID + ' 本单利润间隔：' + str(more_sell_increase))

                            # 去挂单 去sell掉
                            section_sell_newClientOrderId = 'Sell' + cy_config.symbol + str(self.index) + cy_operate.getCurrentTime()

                            current_add_time = cy_operate.getCurrentTime()

                            section_sell_orderid_item = {
                                'price' : section_price,
                                'section_sell_newClientOrderId' : section_sell_newClientOrderId,
                                'is_selled' : False,
                                'current_interval' : more_sell_increase,
                                'add_time' : int(current_add_time)
                            }

                            self.section_sell_orders.append(section_sell_orderid_item)

                            result_v = cy_operate.sellOrder(section_order, section_sell_newClientOrderId, more_sell_increase)

                            if result_v == None:
                                self.section_sell_orders.remove(section_sell_orderid_item)
                                cy_config.more_tao_dan_amount = cy_config.more_tao_dan_amount - 1
                            else:
                                # 把已经去sell的单的id 从检测中设置为已经sell
                                section_buy_order_item['is_sell'] = True

        except Exception as e:
            cy_log.printAndInLog_more('=========== 报错 ============')
            cy_log.printAndInLog_more('检测buy报错信息：' + str(e))
            cy_log.printAndInLog_more('=========== 报错 ============')
        else:
            cy_log.printAndInLog_more('检测buy结束')

    # 去检测之前sell的单，是否已经交易，如果已经交易（被人买了，持仓为空）那么设置区间中对应的价格为未处理状态
    def checkSellOrders(self):

        time.sleep(cy_config.sleep_amount)

        try:
            cy_log.printAndInLog_more('检测Sell的单')
            
            # 使用记录的sell单id，去检测，看是否已经成交（卖出了）

            need_remove_orders = []

            need_check_sell_orders = self.reloadCurrentNeedCHeckSellOrders()

            for section_sell_order_item in self.section_sell_orders:

                time.sleep(cy_config.min_sleep_amount)

                section_orderID = section_sell_order_item['section_sell_newClientOrderId']

                is_can_check = False

                for ned_che_sel_o in need_check_sell_orders:

                    time.sleep(cy_config.min_sleep_amount)

                    ned_che_sel_o_id = ned_che_sel_o['section_sell_newClientOrderId']

                    if section_orderID == ned_che_sel_o_id:
                        is_can_check = True

                if is_can_check:

                    # 获取订单目前的情况
                    section_order = cy_operate.getOrderWithOrderId(section_orderID, True)

                    if section_order:
                        
                        order_status = section_order['state']

                        if order_status == 'filled':

                            cy_config.more_tao_dan_amount = cy_config.more_tao_dan_amount - 1

                            cy_config.more_trad_amount = cy_config.more_trad_amount + 1

                            order_avgPrice = section_order['avgPx']

                            cy_log.printAndInLog_more('SELL 当前订单状态：' + order_status + ' 订单卖出价格：' + order_avgPrice + ' 区间标记价格：' + str(section_sell_order_item['price']) + ' 订单ID：' + section_orderID)

                            section_sell_order_item['is_selled'] = True

                            buy_price = section_sell_order_item['price']
                            buy_price = str(buy_price)

                            updateTime = section_order['uTime']
                            executedQty = section_order['fillSz']

                            # (成交价格 * 成交量 - 买入价格 * 成交量) / 杠杆 = 盈利

                            yinli = (float(order_avgPrice) * float(executedQty) - float(buy_price) * float(executedQty))
                            yinli = str(yinli)

                            if cy_config.is_use_database:
                                server_config.insertYinliData(buy_price, order_avgPrice, updateTime, yinli, 'LONG', executedQty)

                        elif order_status == 'canceled':

                            # 如果订单取消了也减
                            cy_log.printAndInLog_more("订单撤销")
                            cy_config.more_tao_dan_amount = cy_config.more_tao_dan_amount - 1
                            need_remove_orders.append(section_sell_order_item)
                        
                        elif order_status == 'expired':
                            cy_log.printAndInLog_more("订单过期")
                            need_remove_orders.append(section_sell_order_item)
                    else:
                        need_remove_orders.append(section_sell_order_item)
                        cy_log.printAndInLog_more('报错 SELL 订单不存在：' + section_orderID)

            # 删除无用的数据
            for n_r_o in need_remove_orders:
                time.sleep(cy_config.min_sleep_amount)

                self.section_sell_orders.remove(n_r_o)

        except Exception as e:
            cy_log.printAndInLog_more('=========== 报错 ============')
            cy_log.printAndInLog_more('报错信息：' + str(e))
            cy_log.printAndInLog_more('=========== 报错 ============')
        else:
            cy_log.printAndInLog_more('检测sell结束')

    # 使用价格区间内的价格去下单，是否操作字段is_operate 需要是1 才会去下单
    def sectionsToBuy(self):

        try:

            cy_log.printAndInLog_more('区间下单')

            last_price = cy_operate.getCurrentPrice()

            for section_price_item in self.current_section_prices:

                time.sleep(cy_config.min_sleep_amount)

                section_price = section_price_item['price']

                # 下单时候的价格不能超过目前币种的最新价 设置所有超过的为不可操作
                if section_price > last_price:

                    section_price_item['is_operate'] = False

                is_operate = section_price_item['is_operate']

                if is_operate == True:

                    if self.sectionPriceInBuysOrSells(section_price):
                        # 存在不可以购买，并且设置为不可以操作
                        cy_log.printAndInLog_more('存在不可以购买，并且设置为不可以操作')
                        section_price_item['is_operate'] = False
                    else:

                        section_quantity = cy_operate.getMoreQuantityWithPrice(cy_config.more_buy_quantity_by_u, section_price)
                        section_newClientOrderId = 'Buy' + cy_config.symbol + str(self.index) + cy_operate.getCurrentTime()

                        current_add_time = cy_operate.getCurrentTime()

                        section_buy_orderid_item = {
                            'price' : section_price,
                            'section_buy_newClientOrderId' : section_newClientOrderId,
                            'is_sell' : False,
                            'current_interval' : cy_config.more_sell_increase,
                            'add_time' : int(current_add_time)
                        }

                        self.section_buy_orders.append(section_buy_orderid_item)

                        # 如果下单失败 那么就删除数组中对应的id
                        cy_log.printAndInLog_more('下单信息：' + str(section_price) + ' ' + section_newClientOrderId)

                        response_order = cy_operate.tobuy(cy_config.symbol, section_price, section_quantity, section_newClientOrderId)

                        if response_order == None:
                            # 下单失败
                            cy_log.printAndInLog_more('下单失败，从数组中移除')
                            self.section_buy_orders.remove(section_buy_orderid_item)
                        else:
                            cy_log.printAndInLog_more('下单成功，设置为不可以操作')
                            # 等操作完成那么设置是否可以操作为false
                            section_price_item['is_operate'] = False

            # 去见下单结束后，先停一秒
            time.sleep(1)

        except Exception as e:
            cy_log.printAndInLog_more('=========== 报错 ============')
            cy_log.printAndInLog_more('报错信息：' + str(e))
            cy_log.printAndInLog_more('=========== 报错 ============')
        else:
            cy_log.printAndInLog_more('区间下单结束')

    def sectionPriceInBuysOrSells(self, section_price):

        time.sleep(cy_config.sleep_amount)

        cy_log.printAndInLog_more('查询价格是否在本地buys中：' + str(section_price))

        is_in_buys_has = False

        for bus_order in self.section_buy_orders:

            time.sleep(cy_config.min_sleep_amount)

            buy_order_price = bus_order['price']
            buy_order_is_sell = bus_order['is_sell']

            # 先获取价格一样的，然后再去获取状态是NEW或者是PARTIALLY_FILLED
            if float(section_price) == float(buy_order_price) and buy_order_is_sell == False:
                cy_log.printAndInLog_more('存在价格相同的，并且还没有成交的buy')
                is_in_buys_has = True

        is_in_sells_has = False

        # 再把buys中已经存在的单，在sections中设置为false（这个时候buys中已经全是有效的订单了）
        for sells_order in self.section_sell_orders:

            time.sleep(cy_config.min_sleep_amount)

            sell_order_price = sells_order['price']
            sell_order_isSelled = sells_order['is_selled']

            if float(section_price) == float(sell_order_price) and sell_order_isSelled == False:
                cy_log.printAndInLog_more('存在价格相同的，并且还没有成交的sell')
                is_in_sells_has = True

        if len(self.section_buy_orders) or len(self.section_sell_orders):

            if is_in_buys_has:
                # 没有成交  那么不可以购买
                cy_log.printAndInLog_more('存在于buyss中, 没有成交 不可以购买')
                return True
            else:
                # 不存在于buys 那么查看一下sells
                if is_in_sells_has:
                    # 存在于sells中 并且没有成交 那么看一下状态
                    cy_log.printAndInLog_more('存在于sells中, 没有成交 不可以购买')
                    return True
                else:
                    # 既不存在sell中，也不存在buys 那么可以购买
                    return False
        else:
            # 为空 可以购买
            cy_log.printAndInLog_more('buys和sells全为空，可以购买')
            return False

    # 删除在buys中已经撤销的订单
    def clearBuysCelcelOrder(self):

        time.sleep(cy_config.sleep_amount)

        try:

            cy_log.printAndInLog_more('删除在buys中已经撤销的订单')

            need_removes = []

            for section_b_os in self.section_buy_orders:

                time.sleep(cy_config.min_sleep_amount)

                section_orderID = section_b_os['section_buy_newClientOrderId']
                buy_order_is_sell = section_b_os['is_sell']

                if buy_order_is_sell == False:

                    section_order = cy_operate.getOrderWithOrderId(section_orderID, True)

                    if section_order:
                        
                        order_status = section_order['state']

                        if order_status == 'canceled' or order_status == 'expired':
                            # 是已经撤销的，失效的 所以就删除
                            need_removes.append(section_b_os)

            for n_r_o in need_removes:

                time.sleep(cy_config.min_sleep_amount)

                self.section_buy_orders.remove(n_r_o)

        except Exception as e:
            cy_log.printAndInLog_more('=========== 报错 ============')
            cy_log.printAndInLog_more('clearBuysCelcelOrder报错：' + str(e))
            cy_log.printAndInLog_more('=========== 报错 ============')
        else:
            pass

    # 获取当前价格，然后取网格中最靠近当前价格的制定价格对象，设置为可以操作，其余的都设置为不可操作
    def reloadCanTraOrderPrices(self):
        
        time.sleep(cy_config.sleep_amount)

        try:

            # 获取当前价格，然后取网格中最靠近当前价格的制定价格对象，设置为可以操作，其余的都设置为不可操作
            current_price = cy_request.getPrice(cy_config.symbol)

            # 所有小于当前价格的网格
            all_min_prices = []

            for sectionPrice_item in self.current_section_prices:

                time.sleep(cy_config.min_sleep_amount)

                section_price = sectionPrice_item['price']

                if section_price <= float(current_price):

                    all_min_prices.append(sectionPrice_item)

            # 从数组后面开始，获取指定个数的网格
            can_prices = []

            if len(all_min_prices) >= cy_config.can_tar_order_more:
                for index in range(0, cy_config.can_tar_order_more):

                    time.sleep(cy_config.min_sleep_amount)

                    c_index = index + 1
                    can_price = all_min_prices[-c_index]
                    can_prices.append(can_price)
            else:
                # 已经不满足指定个数，所以全部设置为可以操作
                can_prices = all_min_prices

            # 先设置为所有的都为False
            for sectionPrice_item in self.current_section_prices:

                time.sleep(cy_config.min_sleep_amount)

                sectionPrice_item['is_operate'] = False

            # 再设置最近的为True
            for can_price_item in can_prices:
                
                time.sleep(cy_config.min_sleep_amount)

                c_p = can_price_item['price']
                for sectionPrice_item in self.current_section_prices:
                    
                    time.sleep(cy_config.min_sleep_amount)

                    section_price = sectionPrice_item['price']
                    if c_p == section_price:
                        sectionPrice_item['is_operate'] = True

            # 先清空一下bus中已经撤销的单，和别的无效的单
            self.clearBuysCelcelOrder()

            cy_log.printAndInLog_more('循环buys中的单，把不符合的单撤销')

            # 循环buys中的单，把不符合的单撤销
            for section_b_os in self.section_buy_orders:

                time.sleep(cy_config.min_sleep_amount)

                section_orderID = section_b_os['section_buy_newClientOrderId']
                section_price = section_b_os['price']
                buy_order_is_sell = section_b_os['is_sell']

                if buy_order_is_sell == False:

                    isEx = False

                    for can_price_item in can_prices:

                        time.sleep(cy_config.min_sleep_amount)

                        c_p = can_price_item['price']

                        if section_price == c_p:
                            # 不管，正常运行
                            isEx = True

                    if not isEx:
                        # 是需要撤销的
                        section_order = cy_operate.getOrderWithOrderId(section_orderID, True)

                        # 判断订单请求是否正确，如果不正确，就不操作，然后加入到需要删除的数组中
                        if section_order:

                            # 是new，才撤销，不然不管
                            order_status = section_order['state']

                            if order_status == 'live':
                                # 使用id去撤销
                                cencel_order_id = section_order['clOrdId']
                                cy_request.cencel_orderwithCustomerId(cy_config.symbol, cencel_order_id, True)

        except Exception as e:
            cy_log.printAndInLog_more('=========== 报错 ============')
            cy_log.printAndInLog_more('reloadCanTraOrderPrices报错：' + str(e))
            cy_log.printAndInLog_more('=========== 报错 ============')
        else:
            pass

    def toPinc(self):
        
        # 做平仓处理
        more_risk = cy_operate.hasRisk(cy_config.symbol, True)

        cy_log.printAndInLog_more('撤销目前多挂单')
        cencelSymbolOrder.cencelSymbolLongOrder()

        if more_risk:
            cy_log.printAndInLog_more('存在多持仓，平仓')
            cencelSymbolOrder.sellMoreRisk()
        else:
            cy_log.printAndInLog_more('不存在多持仓')

        # 平仓后套单设置成0
        cy_config.more_tao_dan_amount = 0
        # 平仓后卖出订单设置为空
        self.section_sell_orders = []
        # 平仓后买入订单设置为空
        self.section_buy_orders = []
    
    def startReport(self):
        
        try:
            # 获取一下目前的账户金额信息 3秒执行一次
            if cy_config.more_tao_dan_amount >= 10:

                # 判断一下目前持仓回报率
                roe_item = cy_operate.getOpenMoreRoe(cy_config.symbol)
                roe = roe_item['roe']
                amt = roe_item['amt']

                if abs(int(amt)) > 0:
                    # 有持仓
                    # 判断roe
                    if float(roe) > 1.5:

                        cy_log.printAndInLog_more('回报率：' + str(roe) + ' 撤销目前多挂单')
                        cencelSymbolOrder.cencelSymbolLongOrder()
                        cy_log.printAndInLog_more('平仓')
                        cencelSymbolOrder.sellMoreRisk()

                        # 平仓后套单设置成0
                        cy_config.more_tao_dan_amount = 0
                        # 平仓后卖出订单设置为空
                        self.section_sell_orders = []
                        # 平仓后买入订单设置为空
                        self.section_buy_orders = []
                    else:
                        cy_log.printAndInLog_more('目前套单:' + str(cy_config.more_tao_dan_amount) + ' 但是回报率：' + str(roe) + ' 不重启')
                else:
                    cy_log.printAndInLog_more('目前套单:' + str(cy_config.more_tao_dan_amount) + ' 不存在多持仓')
            else:
                cy_log.printAndInLog_more('目前套单:' + str(cy_config.more_tao_dan_amount) + ' 不需要report')
        except Exception as e:
            cy_log.printAndInLog_more('=========== 报错 ============')
            cy_log.printAndInLog_more('重复检测：' + str(e))
            cy_log.printAndInLog_more('=========== 报错 ============')
        else:
            pass

    def getProfitAbout(self):

        # 运行监测
        try:
            profit.open(cy_config.more_tao_dan_amount, cy_config.more_trad_amount, True)
        except Exception as e:
            cy_log.printAndInLog_more('=========== 报错 ============')
            cy_log.printAndInLog_more('监测报错：' + str(e))
            cy_log.printAndInLog_more('=========== 报错 ============')
        else:
            pass

    def open(self):

        try:

            while 1 == 1:

                # 保存套单数据到本地
                cy_operate.saveMoreTaoDanAmountToLocal()

                if cy_config.is_use_database:
                    # 获取服务器配置
                    self.checkConfig()

                # 根据区间倍率 得到当前使用的区间
                self.reloadCurrentQJ()

                # 检测剩下的
                self.checkBuyOrders()
                self.checkSellOrders()

                # 没有到最大套单的时候还是运行
                if cy_config.more_trad_amount < cy_config.max_more_trad_amount:

                    # 设置动态下单的可执行区间
                    self.reloadCanTraOrderPrices()

                    # 用区间价格去下单 开多
                    self.sectionsToBuy()

                else:
                    self.clearBuysCelcelOrder()

                self.getProfitAbout()

                time.sleep(cy_config.sleep_amount)

        except Exception as e:
            cy_log.printAndInLog_more('=========== 报错 ============')
            cy_log.printAndInLog_more('循环报错，停止了：' + str(e))
            cy_log.printAndInLog_more('=========== 报错 ============')
        else:
            cy_log.printAndInLog_more('循环停止了？')